// Package handler 提供HTTP请求处理功能
// 包含RESTful API的路由处理器，负责请求验证、响应格式化等
package handler

import (
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
	"time"

	"ubbc/internal/config"
	"ubbc/internal/model"
	"ubbc/internal/service"
	"ubbc/pkg/logger"
)

// CheckHandler 图片检查处理器结构体
// 处理图片合规性检查的HTTP请求
type CheckHandler struct {
	config       *config.Config        // 应用配置
	checkService *service.CheckService // 检查服务
	logger       *logger.Logger        // 日志记录器
}

// NewCheckHandler 创建新的检查处理器
func NewCheckHandler(cfg *config.Config, checkService *service.CheckService, log *logger.Logger) *CheckHandler {
	return &CheckHandler{
		config:       cfg,
		checkService: checkService,
		logger:       log,
	}
}

// CheckImage 处理图片检查请求
// HTTP端点: POST /api/v1/check-image
func (h *CheckHandler) CheckImage(w http.ResponseWriter, r *http.Request) {
	// 生成请求ID用于追踪
	requestID := h.generateRequestID()
	reqLogger := h.logger.WithRequestID(requestID)

	// 记录请求开始
	startTime := time.Now()
	reqLogger.Info("Received image check request", map[string]interface{}{
		"method":      r.Method,
		"url":         r.URL.String(),
		"user_agent":  r.Header.Get("User-Agent"),
		"remote_addr": r.RemoteAddr,
	})

	// 设置响应头
	w.Header().Set("Content-Type", "application/json")
	w.Header().Set("X-Request-ID", requestID)

	// 验证HTTP方法
	if r.Method != http.MethodPost {
		h.respondError(w, requestID, http.StatusMethodNotAllowed, "METHOD_NOT_ALLOWED", "Only POST method is allowed")
		return
	}

	// 验证API密钥（如果启用）
	if h.config.Security.APIKeyRequired {
		if !h.validateAPIKey(r, requestID) {
			h.respondError(w, requestID, http.StatusUnauthorized, "UNAUTHORIZED", "Invalid or missing API key")
			return
		}
	}

	// 解析请求体
	var req model.CheckImageRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		reqLogger.Error("Failed to decode request body", map[string]interface{}{
			"error": err.Error(),
		})
		h.respondError(w, requestID, http.StatusBadRequest, "INVALID_REQUEST", "Invalid JSON in request body")
		return
	}

	// 验证请求参数
	if err := h.validateRequest(&req, requestID); err != nil {
		h.respondError(w, requestID, http.StatusBadRequest, "INVALID_PARAMETERS", err.Error())
		return
	}

	// 创建请求上下文（带超时）
	ctx, cancel := context.WithTimeout(r.Context(), 60*time.Second)
	defer cancel()

	// 调用检查服务
	result, err := h.checkService.CheckImage(ctx, &req, requestID)
	if err != nil {
		reqLogger.Error("Image check failed", map[string]interface{}{
			"error":     err.Error(),
			"image_url": req.ImageURL,
			"duration":  time.Since(startTime).String(),
		})

		// 根据错误类型返回不同的HTTP状态码
		statusCode := http.StatusInternalServerError
		errorCode := "INTERNAL_ERROR"
		if ctx.Err() == context.DeadlineExceeded {
			statusCode = http.StatusRequestTimeout
			errorCode = "TIMEOUT"
		}

		h.respondError(w, requestID, statusCode, errorCode, "Failed to check image compliance")
		return
	}

	// 记录成功响应
	reqLogger.Info("Image check completed successfully", map[string]interface{}{
		"image_url": req.ImageURL,
		"user_id":   req.UserID,
		"compliant": result.Compliant,
		"duration":  time.Since(startTime).String(),
	})

	// 返回成功响应
	h.respondSuccess(w, result)
}

// Health 健康检查处理器
// HTTP端点: GET /health
func (h *CheckHandler) Health(w http.ResponseWriter, r *http.Request) {
	requestID := h.generateRequestID()

	w.Header().Set("Content-Type", "application/json")
	w.Header().Set("X-Request-ID", requestID)

	// 获取服务统计信息
	stats := h.checkService.GetStats()

	healthResponse := map[string]interface{}{
		"status":     "healthy",
		"timestamp":  time.Now(),
		"request_id": requestID,
		"stats":      stats,
	}

	w.WriteHeader(http.StatusOK)
	json.NewEncoder(w).Encode(healthResponse)
}

// validateAPIKey 验证API密钥
// 检查请求头中的API密钥是否有效
func (h *CheckHandler) validateAPIKey(r *http.Request, requestID string) bool {
	apiKey := r.Header.Get("X-API-Key")
	if apiKey == "" {
		apiKey = r.Header.Get("Authorization")
		if apiKey != "" && len(apiKey) > 7 && apiKey[:7] == "Bearer " {
			apiKey = apiKey[7:]
		}
	}

	isValid := apiKey == h.config.Security.APIKey

	h.logger.WithRequestID(requestID).Debug("API key validation", map[string]interface{}{
		"has_api_key": apiKey != "",
		"is_valid":    isValid,
	})

	return isValid
}

// validateRequest 验证请求参数
// 检查图片URL的格式和有效性
func (h *CheckHandler) validateRequest(req *model.CheckImageRequest, requestID string) error {
	reqLogger := h.logger.WithRequestID(requestID)

	// 验证图片URL是否为空
	if req.ImageURL == "" {
		return fmt.Errorf("image_url is required")
	}

	// 验证URL格式
	parsedURL, err := url.Parse(req.ImageURL)
	if err != nil {
		reqLogger.Error("Invalid URL format", map[string]interface{}{
			"image_url": req.ImageURL,
			"error":     err.Error(),
		})
		return fmt.Errorf("invalid URL format: %s", err.Error())
	}

	// 验证URL协议
	if parsedURL.Scheme != "http" && parsedURL.Scheme != "https" {
		return fmt.Errorf("unsupported URL scheme: %s", parsedURL.Scheme)
	}

	// 验证主机名
	if parsedURL.Host == "" {
		return fmt.Errorf("missing host in URL")
	}

	// 验证域名是否在允许列表中（如果配置了）
	if len(h.config.AllowedDomains) > 0 {
		if !h.isDomainAllowed(parsedURL.Host) {
			reqLogger.Warn("Domain not in allowed list", map[string]interface{}{
				"host":            parsedURL.Host,
				"allowed_domains": h.config.AllowedDomains,
			})
			return fmt.Errorf("domain not allowed: %s", parsedURL.Host)
		}
	}

	reqLogger.Debug("Request validation passed", map[string]interface{}{
		"image_url": req.ImageURL,
		"user_id":   req.UserID,
	})

	return nil
}

// isDomainAllowed 检查域名是否在允许列表中
// 支持通配符匹配
func (h *CheckHandler) isDomainAllowed(host string) bool {
	for _, allowedDomain := range h.config.AllowedDomains {
		if allowedDomain == host {
			return true
		}

		// 支持通配符匹配 (*.example.com)
		if len(allowedDomain) > 2 && allowedDomain[:2] == "*." {
			suffix := allowedDomain[2:]
			if len(host) > len(suffix) && host[len(host)-len(suffix):] == suffix {
				// 检查是否是子域名
				if host[len(host)-len(suffix)-1] == '.' {
					return true
				}
			}
		}
	}
	return false
}

// respondSuccess 返回成功响应
func (h *CheckHandler) respondSuccess(w http.ResponseWriter, data interface{}) {
	w.WriteHeader(http.StatusOK)
	if err := json.NewEncoder(w).Encode(data); err != nil {
		h.logger.Error("Failed to encode success response", "", map[string]interface{}{
			"error": err.Error(),
		})
	}
}

// respondError 返回错误响应
// 统一的错误响应格式
func (h *CheckHandler) respondError(w http.ResponseWriter, requestID string, statusCode int, errorCode, message string) {
	w.WriteHeader(statusCode)

	errorResp := model.ErrorResponse{
		Error:     errorCode,
		Message:   message,
		RequestID: requestID,
		Timestamp: time.Now(),
	}

	if err := json.NewEncoder(w).Encode(errorResp); err != nil {
		h.logger.Error("Failed to encode error response", requestID, map[string]interface{}{
			"error":       err.Error(),
			"status_code": statusCode,
			"error_code":  errorCode,
		})
	}
}

// generateRequestID 生成请求ID
// 用于请求追踪和日志关联
func (h *CheckHandler) generateRequestID() string {
	return fmt.Sprintf("req_%d", time.Now().UnixNano())
}

// SetupRoutes 设置路由
// 配置HTTP路由和中间件
func (h *CheckHandler) SetupRoutes() *http.ServeMux {
	mux := http.NewServeMux()

	// 注册路由
	mux.HandleFunc("/api/v1/check-image", h.logMiddleware(h.CheckImage))
	mux.HandleFunc("/health", h.logMiddleware(h.Health))

	return mux
}

// logMiddleware 日志中间件
// 记录HTTP请求的基本信息
func (h *CheckHandler) logMiddleware(next http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		startTime := time.Now()

		// 创建响应记录器以捕获状态码
		recorder := &responseRecorder{ResponseWriter: w, statusCode: http.StatusOK}

		// 调用下一个处理器
		next(recorder, r)

		// 记录请求完成日志
		h.logger.Info("HTTP request completed", "", map[string]interface{}{
			"method":      r.Method,
			"url":         r.URL.String(),
			"status_code": recorder.statusCode,
			"duration":    time.Since(startTime).String(),
			"remote_addr": r.RemoteAddr,
			"user_agent":  r.Header.Get("User-Agent"),
		})
	}
}

// responseRecorder 响应记录器
// 用于捕获HTTP响应状态码
type responseRecorder struct {
	http.ResponseWriter
	statusCode int
}

// WriteHeader 重写WriteHeader方法以记录状态码
func (rr *responseRecorder) WriteHeader(code int) {
	rr.statusCode = code
	rr.ResponseWriter.WriteHeader(code)
}
